package utils

import (
	"errors"
	"server/global"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

type GenerateTokenClaims struct {
	UserID  string `json:"user_id"`
	IsAdmin bool   `json:"is_admin"`
	jwt.RegisteredClaims
}

/**
 * 生成token
 */
func GenerateToken(userId string, is_admin bool) (*jwt.NumericDate, string, error) {
	if global.GA_CONFIG.Jwt.ExpiresAt < 0 {
		return nil, "", errors.New("无效的过期时间")
	}
	if global.GA_CONFIG.Jwt.NotBefore < 0 {
		return nil, "", errors.New("无效的生效时间")
	}
	expiresAt := jwt.NewNumericDate(time.Now().Add(time.Duration(global.GA_CONFIG.Jwt.ExpiresAt) * time.Second))
	claims := GenerateTokenClaims{
		UserID:  userId,
		IsAdmin: is_admin,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    global.GA_CONFIG.Jwt.Issuer,
			Subject:   global.GA_CONFIG.Jwt.Subject,
			Audience:  jwt.ClaimStrings{global.GA_CONFIG.Jwt.Audience},
			ExpiresAt: expiresAt,
			NotBefore: jwt.NewNumericDate(time.Now().Add(time.Duration(global.GA_CONFIG.Jwt.NotBefore) * time.Second)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := jwtToken.SignedString([]byte(global.GA_CONFIG.Jwt.Secret))
	return expiresAt, token, err
}

/**
* 解析token
 */
func ParseToken(tokenString string) (*GenerateTokenClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &GenerateTokenClaims{}, func(t *jwt.Token) (interface{}, error) {
		return []byte(global.GA_CONFIG.Jwt.Secret), nil
	}, jwt.WithLeeway(2*time.Second))

	if err != nil {
		if errors.Is(err, jwt.ErrTokenExpired) {
			return nil, errors.New("token is expired")
		}
		if errors.Is(err, jwt.ErrTokenNotValidYet) {
			return nil, errors.New("token is not valid yet")
		}
		if errors.Is(err, jwt.ErrTokenInvalidId) {
			return nil, errors.New("token is invalid")
		}
		return nil, err
	}

	claims, ok := token.Claims.(*GenerateTokenClaims)
	if ok && token.Valid {
		return claims, nil
	}
	return nil, jwt.ErrTokenInvalidId
}

func RefreshToken(tokenString string) (string, error) {
	claims, err := ParseToken(tokenString)
	if err != nil {
		return "", err
	}
	if global.GA_CONFIG.Jwt.RefreshAt < 0 {
		return "", errors.New("无效的过期时间")
	}
	if global.GA_CONFIG.Jwt.NotBefore < 0 {
		return "", errors.New("无效的生效时间")
	}
	refreshExpiresAt := jwt.NewNumericDate(time.Now().Add(time.Duration(global.GA_CONFIG.Jwt.RefreshAt) * time.Second))
	tokenClaims := GenerateTokenClaims{
		UserID:  claims.UserID,
		IsAdmin: claims.IsAdmin,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    claims.Issuer,
			Subject:   claims.Subject,
			Audience:  claims.Audience,
			ExpiresAt: refreshExpiresAt,
			NotBefore: jwt.NewNumericDate(time.Now()),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, tokenClaims)
	token, err := jwtToken.SignedString([]byte(global.GA_CONFIG.Jwt.Secret))
	return token, err
}
